package compile;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 命令工具类：
 * 创建进程来运行命令
 */
public class CommandUtil {

    /**
     * 创建一个进程来执行命令：
     * 1. 通过 Runtime 类得到 Runtime 实例, 执行 exec 方法
     * 2. 获取到标准输出, 并写入到指定文件中.
     * 3. 获取到标准错误, 并写入到指定文件中.
     * 4. 等待子进程结束, 拿到子进程的状态码, 并返回.
     * @param cmd 要执行的命令
     * @param stdoutFile 标准输出文件路径
     * @param stderrFile 错误输出文件路径
     * @return
     */
    public static int run(String cmd, String stdoutFile, String stderrFile) {
        try {
            // 1. 通过 Runtime 类得到 Runtime 实例, 执行 exec 方法
            Process process = Runtime.getRuntime().exec(cmd);
            // 2. 获取到标准输出, 并写入到指定文件中.
            if (stdoutFile != null) {
                // 先通过输入流获取运行的进程中的标准输出
                InputStream stdoutFrom = process.getInputStream();
                // 再根据标准输出文件路径，构造一个文件输出流，来保存进程输出的内容
                FileOutputStream stdoutTo = new FileOutputStream(stdoutFile);
                // 循环读取进程输出，并写入标准输出文件中
                while (true) {
                    // 读取一个字符
                    int ch = stdoutFrom.read();
                    // 结束
                    if (ch == -1) {
                        break;
                    }
                    // 写入文件中
                    stdoutTo.write(ch);
                }
                // 关闭流
                stdoutFrom.close();
                stdoutTo.close();
            }
            // 3. 获取到标准错误, 并写入到指定文件中.
            if (stderrFile != null) {
                // 通过输入流获取进程的错误输出内容
                InputStream stderrFrom = process.getErrorStream();
                // 根据错误输出文件路径，构造一个文件输出流，保存进程错误信息
                FileOutputStream stderrTo = new FileOutputStream(stderrFile);
                // 循环读取进程错误输出
                while (true) {
                    // 读取一个字符
                    int ch = stderrFrom.read();
                    // 如果结束
                    if (ch == -1) {
                        break;
                    }
                    // 写入错误输出文件中
                    stderrTo.write(ch);
                }
                // 关闭流
                stderrFrom.close();
                stderrTo.close();
            }
            // 4. 等待子进程结束, 拿到子进程的状态码, 并返回.
            int exitCode = process.waitFor();
            return exitCode;
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return 1;
    }

    /**
     * 单元测试：验证运行命令功能
     * @param args
     */
    public static void main(String[] args) {
        CommandUtil.run("javac", "stdout.txt", "stderr.txt");
    }
}
